#include "mqtt_subscriber.h"

#include <mqtt/connect_options.h>
#include <mqtt/properties.h>
#include <mqtt/subscribe_options.h>

#include <chrono>
#include <iostream>
#include <thread>
#include <tuple>
// 订阅者回调：消息到达处理
void SubscriberCallback::message_arrived(mqtt::const_message_ptr msg) {
  std::cout << "\n[订阅者] 收到消息:" << std::endl;
  std::cout << "  主题: " << msg->get_topic() << std::endl;
  std::cout << "  内容: " << msg->to_string() << std::endl;
  std::cout << "  QoS: " << msg->get_qos() << std::endl;

  // 解析 MQTT 5.0 消息属性
  const auto& props = msg->get_properties();
  if (!props.empty()) {
    std::cout << "  MQTT 5.0 消息属性:" << std::endl;
    for (const auto& prop : props) {
      // 用 prop.type() 获取属性ID（替代 id()/get_id()）
      switch (static_cast<int>(prop.type())) {
        // 有效载荷格式（1字节整数）
        case mqtt::property::PAYLOAD_FORMAT_INDICATOR: {
          uint8_t pfi = mqtt::get<uint8_t>(prop);
          std::cout << "    有效载荷格式: " << (pfi ? "UTF-8" : "未指定")
                    << std::endl;
          break;
        }
        // 消息过期时间（4字节整数）
        case mqtt::property::MESSAGE_EXPIRY_INTERVAL: {
          uint32_t expiry = mqtt::get<uint32_t>(prop);
          std::cout << "    消息过期时间: " << expiry << " 秒" << std::endl;
          break;
        }
        // 内容类型（字符串）
        case mqtt::property::CONTENT_TYPE: {
          std::string ct = mqtt::get<std::string>(prop);
          std::cout << "    内容类型: " << ct << std::endl;
          break;
        }
        // 用户属性（键值对，string_pair）
        case mqtt::property::USER_PROPERTY: {
          auto up = mqtt::get<mqtt::string_pair>(prop);
          std::string key = std::get<0>(up);
          std::string value = std::get<1>(up);
          std::cout << "    用户属性: " << key << " = " << value << std::endl;
          break;
        }
        default:
          std::cout << "    其他属性: " << prop.type_name() << std::endl;
          break;
      }
    }
  }
}

// 订阅者回调：连接丢失处理
void SubscriberCallback::connection_lost(const std::string& cause) {
  std::cerr << "\n[订阅者] 连接丢失: " << (cause.empty() ? "未知原因" : cause)
            << std::endl;
  std::cout << "[订阅者] 尝试重新连接..." << std::endl;
}

// 订阅者回调：发布完成（空实现）
void SubscriberCallback::delivery_complete(mqtt::delivery_token_ptr token) {}

// 订阅者类构造函数
MQTTSubscriber::MQTTSubscriber(const std::string& broker,
                               const std::string& client_id)
    : broker_address_(broker), client_id_(client_id),
      client_(broker, client_id), is_connected_(false) {}

// 订阅者类析构函数
MQTTSubscriber::~MQTTSubscriber() {
  DisConnect();  // 释放客户端资源
}

// 连接到 MQTT broker
bool MQTTSubscriber::Connect() {
  // 设置5.0新特性——连接属性设置
  mqtt::properties conn_props{
      {mqtt::property::SESSION_EXPIRY_INTERVAL,
       3600U},  // 设置会话过期时间为一个小时
      {mqtt::property::RECEIVE_MAXIMUM,
       50U},  // 设置能接收的最大未确认消息数为50条
      {mqtt::property::MAXIMUM_PACKET_SIZE, 131072U},  // 设置能最大消息的字节数
  };
  conn_opts_.set_properties(conn_props);  // 将新特性放入connect_opts中

  conn_opts_.set_clean_start(false);       //   恢复会话，保留以前的会话
  conn_opts_.set_keep_alive_interval(60);  // 设置60秒没通信就断开连接

  client_.set_callback(callback_);  //  设置回调
  std::cout << "连接到: " << broker_address_ << std::endl;
  client_.connect(conn_opts_)->wait();  // 等待连接成功连接
  is_connected_ = client_.is_connected();
  if (is_connected_) {
    std::cout << "连接成功!" << std::endl;
  } else {
    std::cerr << "连接失败" << std::endl;
  }
  return is_connected_;
}

// 断开连接
void MQTTSubscriber::DisConnect() {
  if (is_connected_) {
    mqtt::disconnect_options disc_opts;
    mqtt::properties disc_props{
        {mqtt::property::SESSION_EXPIRY_INTERVAL, 3600U}};
    disc_opts.set_properties(disc_props);

    auto token = client_.disconnect(disc_opts);
    if (token->wait_for(std::chrono::seconds(3))) {
      is_connected_ = false;
      std::cout << "[订阅者] 已断开连接" << std::endl;
    } else {
      std::cerr << "[订阅者] 断开连接超时" << std::endl;
    }
  }
}

// 订阅指定主题
bool MQTTSubscriber::Subscribe(const std::string& topic, int qos) {
  // 设置消息属性
  mqtt::subscribe_options sub_opts;
  mqtt::properties sub_props{{mqtt::property::SUBSCRIPTION_IDENTIFIER, 1U}};

  auto token = client_.subscribe(topic, qos, sub_opts, sub_props);
  if (token->wait_for(std::chrono::seconds(3))) {
    std::cout << "[订阅者] 订阅成功: " << topic << " [QoS: " << qos << "]"
              << std::endl;
    return true;
  }

  std::cerr << "[订阅者] 订阅失败或超时: " << topic << std::endl;
  return false;
}

// 等待接收消息
void MQTTSubscriber::WaitForMessages(int duration) {
  if (!is_connected_) {
    std::cerr << "[订阅者] 未连接，无法等待消息" << std::endl;
    return;
    std::cout << "[订阅者] 等待消息中... (按 Ctrl+C 退出)" << std::endl;
    if (duration > 0) {
      std::this_thread::sleep_for(std::chrono::seconds(duration));
    } else {
      while (is_connected_) {
        std::this_thread::sleep_for(std::chrono::seconds(1));
      }
    }
  }

  std::cout << "[订阅者] 等待消息中... (按 Ctrl+C 退出)" << std::endl;
  if (duration > 0) {
    std::this_thread::sleep_for(std::chrono::seconds(duration));
  } else {
    // 无限等待（直到用户中断）
    while (true) {
      std::this_thread::sleep_for(std::chrono::seconds(1));
    }
  }
}

// 获取连接状态
bool MQTTSubscriber::IsConnected() const {
  return is_connected_;
}